/*
NO OTHER WARRANTIES.  PRINCIPE SOFTWARE DOES NOT WARRANT
THAT THE SOFTWARE IS ERROR FREE.
PRINCIPE SOFTWARE DISCLAIMS ALL OTHER WARRANTIES WITH RESPECT
TO THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT
LIMITED TO IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES
OR LIMITATIONS ON HOW LONG AN IMPLIED WARRANTY MAY LAST, OR THE
EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES,
SO THE ABOVE LIMITATIONS OR EXCLUSIONS MAY NOT APPLY TO YOU.
THIS WARRANTY GIVES YOU SPECIFIC LEGAL RIGHTS AND YOU MAY
ALSO HAVE OTHER RIGHTS WHICH VARY FROM JURISDICTION TO JURISDICTION.

(c) Copyright 2013 Principe Software
All Rights Reserved

*/
#include "stdafx.h"
#include "toknode.h"

//////////////////////////////////////////////////////////////////
// Read: Reads a token
//////////////////////////////////////////////////////////////////
void TokNode::Read(fstream& in)
{
    // Clean structure
    delete data;
    delete astring;

    data = NULL;
    astring = NULL;

    // Read type
    if(!in.read(reinterpret_cast<char *>(&type), sizeof(type)))
        throw new CantReadFile();

    // Locals
    int len;
    wchar_t *buffer = NULL;

    // Is it a string?
    if(type == TT_STRING)
    {
        // Read in length of string
        if(!in.read(reinterpret_cast<char *>(&len), sizeof(len)))
            throw new CantReadFile();

        // Allocate buffer
        buffer = new wchar_t [len+1];

        // Read buffer
        try
        {
            if(!in.read(reinterpret_cast<char *>(buffer), (sizeof(*buffer) * len)))
                throw new CantReadFile();
        }
        catch(...)
        {
            delete [] buffer;
            throw;
        }

        // Add teminating character
        buffer[len] = L'\0';

        // Allocate string
        astring = new wstring;

        // Get buffer
        *astring = buffer;

        delete [] buffer;
    }
    else
    {
        // Allocate data
        data = new TokData;

        // Read data
        switch(type)
        {
        case(TT_SHORT):
            if(!in.read(reinterpret_cast<char *>(&data->short_data), sizeof(short)))
                throw new CantReadFile();
            break;

        case(TT_INT):
            if(!in.read(reinterpret_cast<char *>(&data->int_data), sizeof(int)))
                throw new CantReadFile();
            break;

        case(TT_LONG):
            if(!in.read(reinterpret_cast<char *>(&data->long_data), sizeof(long)))
                throw new CantReadFile();
            break;

        case(TT_FLOAT):
            if(!in.read(reinterpret_cast<char *>(&data->float_data), sizeof(float)))
                throw new CantReadFile();
            break;

        case(TT_DOUBLE):
            if(!in.read(reinterpret_cast<char *>(&data->double_data), sizeof(double)))
                throw new CantReadFile();
            break;

        case(TT_LONG_DOUBLE):
            if(!in.read(reinterpret_cast<char *>(&data->long_double_data), sizeof(long double)))
                throw new CantReadFile();
            break;

        case(TT_TOK):
            if(!in.read(reinterpret_cast<char *>(&data->tok), sizeof(Tok)))
                throw new CantReadFile();
            break;

        }
    }
}

////////////////////////////////////////////////////////////////////////////////////////
// Write: Writes a token
////////////////////////////////////////////////////////////////////////////////////////
void TokNode::Write(fstream& out)
{
    // Locals
    wchar_t *buffer; // The string buffer
    int len; // Length of string

    // Write type
    if(!out.write(reinterpret_cast<char *>(&type), sizeof(type)))
        throw new CantWriteFile();

    // Is it a string?
    if(type == TT_STRING)
    {
        // Write string length
        len = astring->length();

        if(!out.write(reinterpret_cast<char *>(&len), sizeof(len)))
            throw new CantWriteFile();

        // Allocate buffer
        buffer = new wchar_t [len + 1];

        // Get buffer
        wcscpy_s(buffer, astring->length(), astring->c_str());

        // Write buffer
        try
        {
            if(!out.write(reinterpret_cast<char *>(buffer), sizeof(wchar_t) * len))
                throw new CantWriteFile();
        }
        catch(...)
        {
            delete [] buffer;
            throw;
        }
    }
    else
    {
        switch(type)
        {
        case(TT_SHORT):
            if(!out.write(reinterpret_cast<char *>(&data->short_data), sizeof(short)))
                throw new CantWriteFile();
            break;

        case(TT_INT):
            if(!out.write(reinterpret_cast<char *>(&data->int_data), sizeof(int)))
                throw new CantWriteFile();
            break;

        case(TT_LONG):
            if(!out.write(reinterpret_cast<char *>(&data->long_data), sizeof(long)))
                throw new CantWriteFile();
            break;

        case(TT_FLOAT):
            if(!out.write(reinterpret_cast<char *>(&data->float_data), sizeof(float)))
                throw new CantWriteFile();
            break;

        case(TT_DOUBLE):
            if(!out.write(reinterpret_cast<char *>(&data->double_data), sizeof(double)))
                throw new CantWriteFile();
            break;

        case(TT_LONG_DOUBLE):
            if(!out.write(reinterpret_cast<char *>(&data->long_double_data), sizeof(long double)))
                throw new CantWriteFile();
            break;

        case(TT_TOK):
            if(!out.write(reinterpret_cast<char *>(&data->tok), sizeof(Tok)))
                throw new CantWriteFile();
            break;

        }
    }
}

/////////////////////////////////////////////////////////////////////////////////
// Dump: Dumps token
/////////////////////////////////////////////////////////////////////////////////
#ifdef _DEBUG
void TokNode::Dump()
{
	switch (type)
	{
	case(TT_SHORT) :
		cout << "TYPE: short, DATA: " << data->short_data << endl;
		break;

	case(TT_INT) :
		cout << "TYPE: int, DATA: " << data->int_data << endl;
		break;

	case(TT_LONG) :
		cout << "TYPE: long, DATA: " << data->long_data << endl;
		break;

	case(TT_FLOAT) :
		cout << "TYPE: float, DATA: " << data->float_data << endl;
		break;

	case(TT_DOUBLE) :
		cout << "TYPE: double, DATA: " << data->double_data << endl;
		break;

	case(TT_LONG_DOUBLE) :
		cout << "TYPE: long double, DATA: " << data->long_double_data << endl;
		break;

	case(TT_TOK) :
		cout << "TYPE: token, DATA: " << data->tok << endl;
		break;

	case(TT_STRING) :
		wcout << L"TYPE: string, DATA: " << *astring << endl;
		break;

	default:
		cout << "INTERNAL ERROR: Type not reconized" << endl;
		break;
	}
}
#endif